package Graph;
use Math::Complex;

my $dir = './../../sp500-ascii/';
my %gh = ();

sub parseOneStockFile {
	my $in = shift;
	#print "File: $in\n";
	open(F, "$in") || print "Could not open $!\n";
	my %h = ();
	my ($dt, $op, $hi, $lo, $cl, $vo);	
	my $val;
	my ($ticker) = $in =~ /([A-Z]+)\.TXT/;
	foreach my $l (sort <F>) { 
		chomp($l);
		next if ($l =~ /^\s+$/g);
		#print "Line : $l\n";
		($dt, $op, $hi, $lo, $cl, $vo) = split /\s+/, $l;	
		#print "VOL: $vo\n";
		next if (!$dt);
		$h{$dt}{open} = $op;
		$h{$dt}{hi} = $hi;
		$h{$dt}{lo} = $lo;
		$h{$dt}{close} = $cl;
		$h{$dt}{vol} = $vo;
		($h{$dt}{return}, $h{$dt}{deltavol}) = 
			 	($h{$dt-1}) ?
				  (sprintf("%.4f", log(1+$h{$dt}{close}/$h{$dt-1}{close})), $h{$dt}{vol}-$h{$dt-1}{vol}) 
				: (sprintf("%.4f", 0), 0);
		push(@{$gh{$dt}}, "$h{$dt}{return} $ticker");
	}
	return \%h;	
}

sub parseAllStocks {
	opendir(DIR, $dir) || die $!;
	my @files = sort grep {/^AM[A-Z]+\.TXT/} readdir DIR;
	close DIR;
	my %ret = ();
	my $ticker;
	my @tickers;
	foreach my $file (@files) {
		($ticker) = $file =~ /([A-Z]+)\.TXT/;
		$ret{$ticker} = parseOneStockFile("$dir$file");
	}
	return \%ret;
}



# Application sub (Produces Top 10 and Bottom 10 stocks every day)
sub stocksOrderedByReturnsPerDay {
	my @a = ();
	my ($c1, $c2);
	foreach my $date (sort {$b <=> $a} keys %gh) {
		@a = sort {$b <=> $a} @{$gh{$date}};
		$c1 = "@a[0..9]";
		$c1 = ($c1 =~ tr/0\.0000//);
		$c2 = "@a[-10..-1]";
		$c2 = ($c2 =~ tr/0\.0000//);
		next if ($c1 == 60 and $c2 == 60);
		print "$date :\n\t Top 10 : @a[0..9]\n";
		print "\t Bottom 10 : @a[-10..-1]\n";
		print "\n";
	}
}

sub createGraph {
	my $ret = prepareDataFuture();
	use Data::Dumper;
	print Dumper($ret);
	my $data = $ret->{data};
	my $t_pairs = $ret->{tickerpairs};
	my $d_blocks = $ret->{dateblocks};
	my $d_blocks_1 = $ret->{dateblocks_1};
	my $cc = $ret->{crosscorr}; # $cc->{"$t1-$t2"}[$dateblockid] 
	foreach $pair (sort keys %$t_pairs) {
		($t1, $t2) = split /-/, $pair;
		for (my $i ==0; $i< scalar(@{$d_blocks_1->{$t1}}); $i++) {
			if ($cc->{$pair}[$i] >0.8) {
				print "$pair : STRONG POSITIVE CORRELATION\n";
			} elsif ($cc->{$pair}[$i] < -0.8) {
				print "$pair : STRONG NEGATIVE CORRELATION\n";
			} else {
				print "$pair : INSIGNIFICANT\n";
			}
		}
	}
	
}


##############################################################

sub prepareDataFuture {
	my $data = shift || parseAllStocks();
	# $data->{$ticker}{$dt}{return};
	# TICKER PAIRS: $t_pairs->{$ticker1-$ticker2} = 1;
	# DATE BLOCKS: $d_blocks->{$ticker} = [ [500dates],[500dates],...];
	my $t_pairs = getTickerUniquePairs($data);
	my $d_blocks = getDateBlocks($data);
	my $d_blocks_1 = getDateBlocks($data, 1);
	my $returns = {};
	my $cc = {};
	foreach $pair (keys %$t_pairs) {
		($t1, $t2) = split /\-/, $pair; # get tickers
		$a1 = $d_blocks->{$t1}; #array ref of array refs of 500 dates each.
		$a2 = $d_blocks->{$t2};
		$a1_1 = $d_blocks_1->{$t1}; #array ref of 1 offset array refs of 500 dates each.
		$a2_1 = $d_blocks_1->{$t2};
		for (my $i=0; $i<scalar(@$a1); $i++) {
			# collect returns by ticker by chunk ID and by ID
			for (my $j=0; $j<scalar(@{$a1->[$i]}); $j++) {
				# J is date position within an array of 500 dates
				$returns->{$t1}[$i][$j] = $data->{$t1}{$a1->[$i][$j]}{return} || sprintf("%.3f", 0);
				$returns->{$t2}[$i][$j] = $data->{$t2}{$a2->[$i][$j]}{return} || sprintf("%.3f", 0);
				$returns->{$t1."_1"}[$i][$j] = $data->{$t1}{$a1_1->[$i][$j]}{return} || sprintf("%.3f", 0);
				$returns->{$t2."_1"}[$i][$j] = $data->{$t2}{$a2_1->[$i][$j]}{return} || sprintf("%.3f", 0);
			}
			$cc->{$t1.'-'.$t2}[$i] = calcCC($returns->{$t1}[$i], $returns->{$t2."_1"}[$i]);
			$cc->{$t2.'-'.$t1}[$i] = calcCC($returns->{$t2}[$i], $returns->{$t1."_1"}[$i]);
		}
	}
	my $ret = {
			data=>$data,
			tickerpairs=>$t_pairs,
			dateblocks=>$d_blocks,
			dateblocks_1=>$d_blocks_1,
			crosscorr=>$cc
	};
	return $ret;
}

sub prepareData {
	my $data = shift || parseAllStocks();
	# $data->{$ticker}{$dt}{return};
	# TICKER PAIRS: $t_pairs->{$ticker1-$ticker2} = 1;
	# DATE BLOCKS: $d_blocks->{$ticker} = [ [500dates],[500dates],...];
	my $t_pairs = getTickerUniquePairs($data);
	my $d_blocks = getDateBlocks($data);
	my $returns = {};
	my $cc = {};
	foreach $pair (keys %$t_pairs) {
		($t1, $t2) = split /\-/, $pair; # get tickers
		$a1 = $d_blocks->{$t1}; #array ref of array refs of 500 dates each.
		$a2 = $d_blocks->{$t2};
		for (my $i=0; $i<scalar(@$a1); $i++) {
			# I = block id of dates blocks
			# pick array with least # dates, use that for x corr returns 
			$a->[$i] = (scalar(@{$a1->[$i]}) < scalar(@{$a2->[$i]})) ? 
						$a1->[$i] : $a2->[$i];
			print "Ticker:: $t1-$t2\n\t";
			# collect returns by ticker by chunk ID and by ID
			for (my $j=0; $j<scalar(@{$a->[$i]}); $j++) {
				# J is date position within an array of 500 dates
				$returns->{$t1}[$i][$j] = $data->{$t1}{$a->[$i][$j]}{return};
				$returns->{$t2}[$i][$j] = $data->{$t2}{$a->[$i][$j]}{return};
				print "$t1 : $data->{$t1}{$a->[$i][$j]}{return}\t $t2 : $data->{$t2}{$a->[$i][$j]}{return}\n";
			}
			$cc->{$pair}[$i] = calcCC($returns->{$t1}[$i], $returns->{$t2}[$i]);
		}
	}
	return $cc;
}

sub getDateList {
	my $data = shift || parseAllStocks();
	my @tickers = sort keys %$data;
	my @dt;
	my $dates = {};
	foreach $t (@tickers) {
		@dt = sort keys %{$data->{$t}};
		$dates->{$_}++ foreach (@dt);
	}
	return (sort keys %$dates);
}

sub getDateBlocks {
	my $data = shift || parseAllStocks();
	my $offset = shift || 0;
	my @tickers = sort keys %$data;
	my @dates;
	my $out = {};
	foreach $t (@tickers) {
		@dates = sort keys %{$data->{$t}};
		my @chunks = ();
		shift(@dates) if ($offset == 1);
		while (@dates) {
			my @chunk = splice(@dates,0,500);
			push(@chunks, \@chunk);
		}
		$out->{$t} = \@chunks;
	}
	return $out;
}

sub getTickerUniquePairs {
	my $data = shift || parseAllStocks();
	@tickers = (sort keys %$data);
	my %count_of;
	foreach my $i ( 0 .. $#tickers - 1 ) {
        foreach my $j ( $i+1 .. $#tickers ) {
            $count_of{ $tickers[$i] . q{-} . $tickers[$j] }++;
        }
    }
	return \%count_of;
}

# calculating cross correlation

sub getReturns {
	my $data = shift || parseAllStocks();
	my @allres;
	my @res=();
	#my $c = 0;
	my $tmpres = ref ();
	foreach my $ticker (sort keys %$data) {
		next if ($ticker !~ /[A-Z]+/);
		#print "Ticker: $ticker\n";
		push(@res, $ticker);
		#$c = 0;
		foreach my $dt (sort keys %{$data{$ticker}}) {
			#last if ($c == 5);
			next if ($dt !~ /\d{8}/);
			#print "\tdate: $dt\n";
			#$c++;
			push(@res, $dt, $data{$ticker}{$dt}{return});
			#print "\t return: $data{$ticker}{$dt}{return} \n";
		}
		push(@$tmpres, @res) if (scalar(@res));
		push(@allres, $tmpres) if ($tmpres);
		$tmpres = undef;
		@res = ();
	}
	#print "\n\n\n ALL RES \n";
	return \@allres;
}

# calculating cross correlation

sub average {
	my $arr = shift;
	my $sum;
	foreach my $i (@{$arr}) {
		$sum += $i;
	} 
	my $avg = sprintf("%.2f", $sum/scalar(@{$arr})) if (scalar(@{$arr}) != 0);
	return $avg;
}

sub crossAverage {
	my ($arr1, $arr2) = @_;
	my $sum;
	for (my $i=0; $i< scalar(@{$arr1}); $i++) {
		$sum += $arr1->[$i] * $arr2->[$i];
	} 
	my $avg = (scalar(@{$arr1})) ? $sum/scalar(@{$arr1}) : 0;
	return $avg;
}

sub variance {
	my $arr1 = shift;
	my $avg_sq = 0;
	for (my $i =0; $i<scalar(@$arr1); $i++) {
		$avg_sq += $arr1->[$i] * $arr1->[$i];
	}
	$avg_sq /= scalar(@$arr1) if (scalar(@$arr1) != 0);
	my $var = $avg_sq - average($arr1) * average($arr1);
	return $var;
}

sub calcCC {
	my ($arr1, $arr2) = @_;
	#print "LEN ARR1: ". scalar(@$arr1) . " LEN ARR2: " . scalar(@$arr2). "\n";
	my $numerator = crossAverage($arr1, $arr2) - average($arr1)*average($arr2);
	my $denominator = sqrt(variance($arr1)*variance($arr2));
	my $cc = $numerator/$denominator if ($denominator != 0);
	$cc = ($cc) ? $cc : 0;
	return sprintf("%.3f", $cc);
}

sub parseConfFile {
}

sub dataHash {
}


1;

